package com.onpositive.knowledge.model.values;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import com.onpositive.knowledge.model.value.audits.AbstractAuditResult;
import com.onpositive.knowledge.model.value.audits.GeneralAuditResult;
import com.onpositive.knowledge.model.value.audits.ValueSequenceOrderingAudit;
import com.onpositive.semantic.model.api.property.IProperty;
import com.onpositive.units.ParsedString;
import com.onpositive.units.ParsedValue;
import com.onpositive.units.ParsedValueSequence;

public class ValueSequenceOrderingTransformer extends AuditAssistedTransformer {

	private static final long serialVersionUID = -1070426168300984555L;
	public static final String ID = "value-sequence-ordering-transformer" ; 

	public ValueSequenceOrderingTransformer(IHasAuditResult src) {
		super(src);
	}

	@Override
	public DescribedValue[] adjust(Object object, IProperty prop, DescribedValue... original) {

		String name = prop.getMeta().getSingleValue( "id", String.class, null ) ;	
		
		AbstractAuditResult aResult = this.getAuditResultSource().getAuditResult() ;
		
		ValueSequenceOrderingAudit.OwnAuditResult proposals = null ;
		
		if( aResult instanceof ValueSequenceOrderingAudit.OwnAuditResult )
			proposals = (ValueSequenceOrderingAudit.OwnAuditResult)aResult ;

		else if( aResult instanceof GeneralAuditResult )
		{
			GeneralAuditResult gResult = (GeneralAuditResult) aResult ;
			AbstractAuditResult result = gResult.getResult( ValueSequenceOrderingAudit.ID );
			if(  !(result instanceof ValueSequenceOrderingAudit.OwnAuditResult))
				return original ;
			proposals = (ValueSequenceOrderingAudit.OwnAuditResult) result ;			
		}
		
		if( proposals != null  )			
			return doAdjust( prop, proposals, original );
		
		return original ;
	}

	private DescribedValue[] doAdjust( IProperty prop, ValueSequenceOrderingAudit.OwnAuditResult proposals, DescribedValue[] original) {
		
		ArrayList<DescribedValue> result = new ArrayList<DescribedValue>() ;
		
		boolean gotAGlobalchange = false ;
		for( DescribedValue dv : original )
		{
			Object valueObject = dv.value();
			if( valueObject == null || !(valueObject instanceof ParsedValueSequence) )
			{
				result.add(dv) ;
				continue ;
			}
			ParsedValueSequence pvs = (ParsedValueSequence) valueObject ;
			ParsedValueSequence new_pvs = new ParsedValueSequence("ord-transf " + pvs.getComment()) ;
			
			Object parsedValueSet = pvs.value() ;
			if( parsedValueSet == null )
			{
				result.add(dv) ;
				continue ;
			}
			
			LinkedHashSet<ParsedValue> set = (LinkedHashSet<ParsedValue>) parsedValueSet ;
			int size = set.size();
			if( size < 2 )
				continue ;
			
			ParsedValue[] valArr = new ParsedValue[ size ] ;
			set.toArray(valArr) ;
			
			boolean gotAChange = false ;
			String comment = null ;
			byte infered = 0;
			for( int i = 1 ; i < size ; i ++ )
			{
				if( !( valArr[ i ] instanceof ParsedString) )
				{
					new_pvs.addValue( valArr[i-1] ) ;
					new_pvs.addValue( valArr[ i ] ) ;
					i++ ;
					continue ;
				}
				
				if( !( valArr[i-1] instanceof ParsedString) ){
					new_pvs.addValue( valArr[i-1] ) ;
					if(i==size-1)
						new_pvs.addValue( valArr[i] ) ;
					continue ;
				}
				
				String s0 = ((ParsedString)valArr[i-1]).getValueAsString() ; 
				String s1 = ((ParsedString)valArr[i  ]).getValueAsString() ;
				
				boolean firstIsSmallerThenSecond = s0.compareTo(s1) < 0 ;
				String keyString = firstIsSmallerThenSecond ? s0+s1 : s1+s0 ;
				
				HashMap<String,Boolean> correctionsMap = proposals.getCorrectionsMap( prop.getId() );
				if( correctionsMap == null )
					return original ;
				
				Boolean firstShouldBeSmallerThenSecond = correctionsMap.get(keyString) ;
				if( firstShouldBeSmallerThenSecond == null || firstShouldBeSmallerThenSecond == firstIsSmallerThenSecond )
				{
					new_pvs.addValue( valArr[i-1] ) ;
					if(i==size-1)
						new_pvs.addValue( valArr[i] ) ;
					continue ;					
				}			
					
				gotAChange = true ;
				new_pvs.addValue( valArr[ i ] ) ;
				new_pvs.addValue( valArr[i-1] ) ;			
				i++ ;
			}
			if( gotAChange )
			{
				DescribedValue newDv = new DescribedValue( infered, new_pvs, null, comment ) ;
				result.add( newDv) ;
				gotAGlobalchange = true ;
			}
			else
				result.add(dv) ;
			
		}
		return gotAGlobalchange ? result.toArray( new DescribedValue[result.size()] ) : original ;
	}

	@Override
	public String getId() {
		return ID;
	}

}
